#include "config.h"

#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <getopt.h>
#include <dirent.h>
#include <ctype.h>

#define DBG_SUBSYS S_LIBINTERFACE

#include "configure.h"
#include "env.h"
#include "adt.h"
#include "net_table.h"
#include "lichstor.h"
#include "cluster.h"
#include "lich_md.h"
#include "lichbd.h"
#include "license.h"
#include "md_map.h"
#include "net_global.h"
#include "utils.h"
#include "dbg.h"


static int __spare_get_fid_fsfree(const char *pool, fileid_t *fid, uint64_t *fssize, uint64_t *fsfree)
{
        int ret, retry = 0;
        struct statvfs svbuf;

        retry = 0;
retry:
        ret = stor_statvfs(pool, fid, &svbuf);
        if (ret) {
                if (ret == EAGAIN) {
                        USLEEP_RETRY(err_ret, ret, retry, retry, 3, 1000 * 1000);
                } else
                        GOTO(err_ret, ret);
        }

        if (fssize)
                *fssize = svbuf.f_bsize * svbuf.f_blocks;
        if (fsfree)
                *fsfree = svbuf.f_bsize * svbuf.f_bfree;

        return 0;
err_ret:
        return ret;
}


int spare_value2size(const char *pool, const char *value, uint64_t *size)
{
        int ret, pct, retry;
        uint64_t fssize;
        fileid_t fid;

        if (value[strlen(value) - 1] == '%') {
                sscanf(value, "%d%%", &pct);

                if (pct < 0 || pct > 100) {
                        ret = EINVAL;
                        GOTO(err_ret, ret);
                }

                retry = 0;
retry0:
                ret = stor_lookup1(pool, "/", &fid);
                if (ret) {
                        if (ret == EAGAIN) {
                                USLEEP_RETRY(err_ret, ret, retry0, retry, 50, (100 * 1000));
                        } else
                                GOTO(err_ret, ret);
                }

                ret =  __spare_get_fid_fsfree(pool, &fid, &fssize, NULL);
                if (ret)
                        GOTO(err_ret, ret);

                *size = fssize * pct * 0.01;
        } else {

                ret = utils_get_size(value, size);
                if (ret)
                        GOTO(err_ret, ret);
        }

        return 0;
err_ret:
        return ret;
}

int utils_spare_policy(const char *pool)
{
        int ret, buflen, retry;
        char buf[MAX_BUF_LEN];
        uint64_t spare_size, fsfree;

        fileid_t fid;
        nid_t nid;

        retry = 0;
retry0:
        ret = stor_lookup1(pool, "/", &fid);
        if (ret) {
                USLEEP_RETRY(err_ret, ret, retry0, retry, 60, (100 * 1000));
        }

        retry = 0;
retry1:
        ret = md_map_getsrv(&fid, &nid);
        if (ret) {
                USLEEP_RETRY(err_ret, ret, retry1, retry, 60, (100 * 1000));
        }

        retry = 0;
        buflen = MAX_BUF_LEN;
retry2:
        ret = md_xattr_get(&nid, &fid, LICH_SYSTEM_ATTR_SPARE_ERROR, buf, &buflen);
        if (ret) {
                if (ret != ENOKEY) {
                        USLEEP_RETRY(err_ret, ret, retry2, retry, 60, (100 * 1000));
                } else {
                        GOTO(err_ret, ret);
                }
        }

        ret =  __spare_get_fid_fsfree(pool, &fid, NULL, &fsfree);
        if (ret)
                GOTO(err_ret, ret);

        ret = spare_value2size(pool, buf, &spare_size);
        if (ret)
                GOTO(err_ret, ret);

        return !!(fsfree < spare_size);
err_ret:
        ret = !(ret == ENOKEY);
        return ret;
}
